Skip to content

Add support for Model Context Protocol#271

Open
martin-fleck-at wants to merge 1 commit into
masterfrom
issues/1546
Open

Add support for Model Context Protocol#271
martin-fleck-at wants to merge 1 commit into
masterfrom
issues/1546

Conversation

@martin-fleck-at
Copy link
Copy Markdown
Contributor

@martin-fleck-at martin-fleck-at commented Dec 18, 2025

What it does

Registers GLSP-announced MCP servers with the IDE's MCP frontend
service so the agent can use them immediately after IDE startup.

MCP integration

  • Discovers MCP server descriptors on each GLSP client contribution
    and adds them to the IDE's MCP host on startup.
  • Triggers an explicit start since the host's autostart hook only
    fires at frontend init.
  • Per-registration cleanup releases server entries and state-change
    subscriptions on GLSP failure or extension dispose, avoiding
    stale entries across IDE restarts under random-port defaults.

Adopters

  • Set the configuration on the GLSP client contribution to enable
    MCP for a diagram language.
  • The workflow example demonstrates the end-to-end wiring with a
    transient connect notification and a copy-URL action.

Misc

  • Sends a shutdown notification before the GLSP connection drops
    so the server tears down cleanly with the parent session.

Part of eclipse-glsp/glsp#1546
Requires eclipse-glsp/glsp-client#456 and eclipse-glsp/glsp-server-node#120

How to test

  • Nothing should break in the default case
  • To use the new mcp server, you need to use a GLSP server that supports it, i.e., the GLSP Node Server
  • Startup the Workflow example
  • Check the AI Configuration > MCP Server view that should show the GLSP MCP server correctly and allow you to connect to it and show all tools. Please note that there is no support for MCP resources in Theia yet.

Follow-ups

Changelog

  • This PR should be mentioned in the changelog
  • This PR introduces a breaking change (if yes, provide more details below for the changelog and the migration guide)

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for the Model Context Protocol (MCP) by integrating GLSP MCP servers with Theia AI. The changes enable GLSP diagram editors to expose their functionality through MCP servers that can be discovered and utilized by Theia's AI features.

Key changes:

  • New theia-mcp-integration package that automatically registers GLSP MCP servers with Theia's AI MCP service
  • Fixed shutdown notification handling to properly notify servers before connection disposal
  • Updated workflow example to demonstrate MCP server initialization

Reviewed changes

Copilot reviewed 12 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/theia-mcp-integration/package.json Defines new package for MCP integration with dependencies on Theia AI and GLSP integration
packages/theia-mcp-integration/tsconfig.json TypeScript configuration for the new MCP integration package
packages/theia-mcp-integration/src/browser/theia-mcp-integration-frontend-module.ts Container module that registers the MCP registration service
packages/theia-mcp-integration/src/browser/glsp-mcp-registration.ts Service that discovers GLSP clients and registers their MCP servers with Theia
packages/theia-integration/src/browser/glsp-client-contribution.ts Fixed to send shutdown notification before disposing connection
examples/workflow-theia/src/browser/workflow-glsp-client-contribution.ts Updated to include MCP server initialization parameters
examples/workflow-theia/package.json Added dependency on new theia-mcp-integration package
examples/workflow-theia/tsconfig.json Added TypeScript project reference to theia-mcp-integration
examples/browser-app/package.json Added Theia AI dependencies to demonstrate MCP integration
package.json Updated workspace pattern to include all packages
configs/local-linking.sh Added server-mcp package to local linking script
.vscode/launch.json Added debug configuration for server-mcp package

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/theia-integration/src/browser/glsp-client-contribution.ts
Registers GLSP-announced MCP servers with the IDE's MCP frontend
service so the agent can use them immediately after IDE startup.

MCP integration
- Discovers MCP server descriptors on each GLSP client contribution
  and adds them to the IDE's MCP host on startup.
- Triggers an explicit start since the host's autostart hook only
  fires at frontend init.
- Per-registration cleanup releases server entries and state-change
  subscriptions on GLSP failure or extension dispose, avoiding
  stale entries across IDE restarts under random-port defaults.

Adopters
- Set the configuration on the GLSP client contribution to enable
  MCP for a diagram language.
- The workflow example demonstrates the end-to-end wiring with a
  transient connect notification and a copy-URL action.

Misc
- Sends a shutdown notification before the GLSP connection drops
  so the server tears down cleanly with the parent session.

Part of eclipse-glsp/glsp#1546
Comment thread .github/workflows/e2e.yml
env:
STANDALONE_URL: 'file://${{ github.workspace }}/glsp-client/examples/workflow-standalone/app/diagram.html'
GLSP_SERVER_PORT: '8081'
GLSP_MCP_SERVER_PORT: '64577'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this added?
Do we currently even have e2e tests for the mcp feature?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not, so I removed it again.

Comment thread configs/local-linking.sh
# Defensive: stale nested @eclipse-glsp copies from prior installs shadow the workspace
# symlinks via Node's nearest-node_modules-wins resolution → bundle fails.
# Remove them before re-linking.
find packages examples -path '*/node_modules/@eclipse-glsp' -type d -exec rm -rf {} + 2>/dev/null || true
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's worth maintaining this script any longer.
We now have linking functionality built in the glsp cli tool.

We should probably update our repos accordingly.
But that's a thing for a follow-up

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I think so too, should be done in a proper cleanup.

return undefined;
}

protected async getMcpServerPortFromEnv(): Promise<number | undefined> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could probably align this into one getPortFromEnv() method that just takes the env var as parameter
Instead of three more or less identical methods

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea!

this.toDispose.push(
Disposable.create(async () => {
// Await the shutdown so the wire flushes before we dispose the connection.
const client = await this.glspClient;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this.glspClient hasn't resolved yet when dispose fires (e.g., contribution disposed during startup), the await will block the async body indefinitely, and connection.dispose() / channel.dispose() will never execute.
The previous code pushed connection and channel as separate disposables, guaranteeing synchronous cleanu

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! We do a best effort shutdown now if the client already resolved but otherwise we will simply dispose as before.

"scripts": {
"build": "tsc -b",
"clean": "rimraf lib *.tsbuildinfo ",
"generate:index": "glsp generateIndex src/browser src/common src/node -s -f",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"generate:index": "glsp generateIndex src/browser src/common src/node -s -f",
"generate:index": "glsp generateIndex src/browser -s -f",

Generate changelog entries by analyzing merged PRs since the last release.

Execute these phases in order:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CHANGELOG entry formatting changed from - (dash + 3 spaces) to - (dash + 1 space), which contradicts the style guide in SKILL.md line 84 that specifies "Entry prefix: - (dash + exactly 3 spaces)". If this is an intentional style migration,
the SKILL.md should be updated to match. If not, the CHANGELOG entry should retain the original format.

This might be related to the underlying version of prettier/eslint/markdown-lint that is used. I also experienced similar issues in other glsp projects.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prettier actually enforces the 1 space when we do yarn format. I updated the skill for this as it proposes 3 spaces

* override via `rebind(GlspMcpRegistration).to(YourSubclass)` for environments where
* servers should be registered but kept off until the user starts them on-demand.
*/
protected readonly autostart: boolean = true;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the override fluff. (everything after the ;)

* Aggregated cleanup — owns one inner {@link DisposableCollection} per registration. Dispose
* triggers `removeServer` for every registration and drops the state-change subscriptions.
*/
protected readonly toDispose = new DisposableCollection();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to add an additional comment for the general toDispose pattern

* GLSP servers boot on a random port by default, so a registered URL is stale on the next IDE
* launch. Drop our registrations on shutdown so the next session starts fresh.
*/
dispose(): void {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same. no need to comment dispose

// Per-registration cleanup group. Disposing it removes the MCP server entry AND drops the
// state-change subscription. Triggers either on definitive GLSP failure (state listener
// self-disposes) or on extension dispose (parent collection cascades).
const perRegistration = new DisposableCollection(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe remove comment here...

@martin-fleck-at
Copy link
Copy Markdown
Contributor Author

@tortmayr Thank you for your feedback. Once the server is merged, I'll do a final update on the PR integrating all your comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants